msg_tool\scripts\kirikiri\archive\xp3\crypt/
nvl.rs

1use super::*;
2
3#[derive(Debug)]
4pub struct NVLCrypt {
5    base: BaseSchema,
6    key: [u8; 8],
7}
8
9impl NVLCrypt {
10    pub fn new(base: BaseSchema, key: &[u8]) -> Result<Self> {
11        if key.len() != 8 {
12            anyhow::bail!("Key must be 8 bytes.");
13        }
14        Ok(Self {
15            base,
16            key: key.try_into()?
17        })
18    }
19
20    fn get_key(&self, hash: u32) -> [u8; 12] {
21        let mut key = [0; 12];
22        key[..4].copy_from_slice(&hash.to_le_bytes());
23        key[4..].copy_from_slice(&self.key);
24        key
25    }
26}
27
28impl Crypt for NVLCrypt {
29    fn hash_after_crypt(&self) -> bool {
30        self.base.hash_after_crypt
31    }
32    fn startup_tjs_not_encrypted(&self) -> bool {
33        self.base.startup_tjs_not_encrypted
34    }
35    fn obfuscated_index(&self) -> bool {
36        self.base.obfuscated_index
37    }
38    fn read_name<'a>(&self, reader: &mut Box<dyn Read + 'a>) -> Result<(String, u64)> {
39        let hash_key = reader.read_u32()?;
40        let name_hash = reader.read_u32()?;
41        let extension_hash = reader.read_u32()?;
42        Ok((format!("{:08x}.{:08x}", hash_key ^ name_hash, hash_key ^ extension_hash), 12))
43    }
44    fn decrypt_supported(&self) -> bool {
45        true
46    }
47    fn decrypt_seek_supported(&self) -> bool {
48        true
49    }
50    fn decrypt<'a>(
51        &self,
52        entry: &Xp3Entry,
53        cur_seg: &Segment,
54        stream: Box<dyn Read + Send + Sync + 'a>,
55    ) -> Result<Box<dyn ReadDebug + Send + Sync + 'a>> {
56        Ok(Box::new(NVLCryptReader::new(
57            stream,
58            cur_seg,
59            self.get_key(entry.file_hash),
60        )))
61    }
62    fn decrypt_with_seek<'a>(
63        &self,
64        entry: &Xp3Entry,
65        cur_seg: &Segment,
66        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
67    ) -> Result<Box<dyn ReadSeek + Send + Sync + 'a>> {
68        Ok(Box::new(NVLCryptReader::new(
69            stream,
70            cur_seg,
71            self.get_key(entry.file_hash),
72        )))
73    }
74}
75
76impl<R: Read> Read for NVLCryptReader<R> {
77    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
78        let readed = self.inner.read(buf)?;
79        let mut offset = ((self.pos + self.seg_start) % 12) as usize;
80        for t in (&mut buf[..readed]).iter_mut() {
81            *t ^= self.key[offset];
82            offset = (offset + 1) % 12;
83        }
84        self.pos += readed as u64;
85        Ok(readed)
86    }
87}